package service

import (
	"context"
	"encoding/json"
	"errors"
	"github.com/gin-gonic/gin"
	"github.com/go-admin-team/go-admin-core/sdk/service"
	"github.com/go-pay/gopay/wechat/v3"
	"github.com/wechatpay-apiv3/wechatpay-go/core"
	"github.com/wechatpay-apiv3/wechatpay-go/core/option"
	"github.com/wechatpay-apiv3/wechatpay-go/services/payments/app"
	"github.com/wechatpay-apiv3/wechatpay-go/services/transferbatch"
	payUtils "github.com/wechatpay-apiv3/wechatpay-go/utils"
	"log"
	"time"
	"tuowei.com/app/admin/models"
	adminDto "tuowei.com/app/admin/service/dto"
	api "tuowei.com/app/api/models"
	"tuowei.com/app/api/service/dto"
)

const AppiD, Mchid, MchCertificateSerialNumber, MchAPIv3Key = "wxf741b8a76b5eed4f", "1533105481", "75D53DE02B5D5F4DBFB0D08CE1352628EF1FB890", "e92028de6429d6e83ed038d9e723ee83"

const PrivateKey1 = "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDFNP5FoCAE1uYj\nirLMoK0jv5JxoLUWxqobqJlENQYWm7FAfqD1JasIrSehWSmcrIJn3hwyRTHSozh/\nLOoTB/TLWBh1jdoLM/TDbP6xRZI/MeGFvMYebGlNHD+Yb9c7Fd0ns3cdWZuIESXb\neJd1fGDGekoJqoxpsdvAMxga0CMlReuuonUp6eVjIXcDe6La9TCjnbC5TiZ/u3BH\nlyBQ+FtupCrP+YuGSh5bfgTlnAop/hBIwY851cjETuUW8xxRIzdsKMSjxPNmPOZK\nfVca6/HyBZ44qxO+UzDJABfJCMwMZ6KZgf5XTO6uQGvs9FSkByqsgyG93fnDVlCI\nkO717oCjAgMBAAECggEBAKDIK+coPfK0Ir4nfs9G0OKsdgEePYZsQpR6STtK38Pe\n/AzRMPmt1FwmkIED6OFL5KY6eFKkB5LscEt/mvgZLIP9NzPgiz1HBu+uFZkCV9Ie\nIPigiAaV7ORpe5AU3y3VDZIox5yuShgNowfksdefqGcpnON0oTYrRDbXcXeq6nyf\nrO3HNScxMLt3dKqmYufBJfyJ5ywGI0GUhoOV6yNO5Tr4eZOQy7E1pQmBPDs4efMp\nBo7GDozpz6C6chr8V+IFPY9ISuDMT4GRpzBhM5ScZxe8Z4WSsvRKuNlZw8Rq6SAV\nT73Em7QsXt4CHDreAaEuH+SDHGITDCzX+yXzgrtgVAECgYEA+C/eQVwTpe4M0ZDk\n5gp92z1T5b1g5igOGOh7SsskEd8S1DemLT/Wma35oE0tusWFBaoiOORx/XWADiH+\n+zKEE0lcrESgOQoj6x+AjktG63dnscrXlFRhDTkchkWR3a+I9gzf7CBGp/St39Dj\nAaHH0cUsQhwYZm/Kggho1shgOMECgYEAy2pHY4gMLWHM2vHnR1g1V3r8isEkkExe\n/wW+DITmTKgSLcsjf7BFflG6LfSDXclq2fsgcUPBt45i0JF1cB+rmaGZpM3hTj5Z\nQWCIA9kwS6Slq2nUTNMEW+LlsLjdA2QfGycAd/mVJw29CyWQBMhyx5+wGXIX1o5c\ngjKCIE8eDmMCgYEAjqfFEsCAMrIgAB1O1MNXEDuyC63NEr4XTE3lAFq/gt48Dmtm\nQ0Acc/1CLNfv3xlFmrnuLdFxjASL9JOp4m1o6UUT1Zkkl2SyvKVA2Yl/XD0oB1PW\nklXl6xnWwX8fltMc4IEJ/MmYk1Xa03lX4kpBdtvk0qMfi1Hajt+Sk1JdrIECgYA3\n+KF2GKxJHH0Szbc24WWkEZpFz8lwzyLgh0L5DOSVuTVvVlMJQoaMsI5LMNmox9BX\n9IrDv8Ig8NPt0eh/lqdQGbA+McxKDEvg+l/St0NbvQ088lzRWsr7QZ60Ftnxoe4R\nOZUebhWFbnlTBN3xAvraRO1eww8eIYQA60b0/vAlQwKBgFuJAbn6Vnu88v5E2v+a\nJUGbVmhz1xKMmHR8ahT8Z86VW+PgtB/CXuXTAcZlJJi36iRR/BQR95SMTTVxHy9t\nu+sGHWChLh8Nzz19uYMA/pcIEy77sPFpLZ7WKIBB2Rg/JpsVZQkog1OdTTqTEdrh\ngJAEHmqiWrHxtJ1MZuVlQyPw\n-----END PRIVATE KEY-----\n"

const MchPKFileName = "apiclient_key.pem"

//const WXNotifyUrl = "http://test_api.twzxjy.com:8000/api/v1/wxpay/callback"

//获取加解密处理
func getWechatClient() (context.Context, *core.Client, error) {
	// 使用 utils 提供的函数从本地文件中加载商户私钥，商户私钥会用来生成请求的签名
	mchPrivateKey, err := payUtils.LoadPrivateKey(PrivateKey1)
	if err != nil {
		log.Print("load merchant private key error")
		return nil, nil, err
	}

	ctx := context.Background()
	// 使用商户私钥等初始化 client，并使它具有自动定时获取微信支付平台证书的能力
	opts := []core.ClientOption{
		option.WithWechatPayAutoAuthCipher(Mchid, MchCertificateSerialNumber, mchPrivateKey, MchAPIv3Key),
	}
	client, err := core.NewClient(ctx, opts...)
	if err != nil {
		log.Printf("new wechat pay client err:%s", err)
		return nil, nil, err
	}
	return ctx, client, nil
}

func CreateWechatPrepayBill(outTradeNo, description, attach string, amount int64) (string, error) {
	notifyUrl := WXNotifyUrl
	ctx, client, err := getWechatClient()
	if err != nil {
		log.Printf("new wechat pay client err:%s", err)
		return "", err
	}

	tmp, _ := time.ParseDuration("5m")
	endTime := time.Now().Add(tmp)
	svc := app.AppApiService{Client: client}
	resp, result, err := svc.Prepay(ctx,
		app.PrepayRequest{
			Appid:         core.String(AppiD),
			Mchid:         core.String(Mchid),
			Description:   core.String(description),
			OutTradeNo:    core.String(outTradeNo),
			TimeExpire:    core.Time(endTime),
			Attach:        core.String(attach),
			NotifyUrl:     core.String(notifyUrl),
			GoodsTag:      core.String("WXG"),
			LimitPay:      []string{"no_credit"},
			SupportFapiao: core.Bool(false),
			Amount: &app.Amount{
				Currency: core.String("CNY"),
				Total:    core.Int64(amount),
			},
			SettleInfo: &app.SettleInfo{
				ProfitSharing: core.Bool(false),
			},
		},
	)

	if err != nil {
		// 处理错误
		log.Printf("call Prepay err:%s", err)
		return "", nil
	} else {
		// 处理返回结果
		log.Printf("status=%d resp=%s", result.Response.StatusCode, resp)
	}
	return *resp.PrepayId, nil
}

//创建并生成待支付信息
func CreateWechatPrepayWithPayment(outTradeNo, description, attach string, amount int64) (map[string]interface{}, error) {
	notifyUrl := WXNotifyUrl
	ctx, client, err := getWechatClient()
	if err != nil {
		return nil, err
	}

	tmp, _ := time.ParseDuration("5m")
	endTime := time.Now().Add(tmp)
	svc := app.AppApiService{Client: client}
	resp, _, err := svc.PrepayWithRequestPayment(ctx,
		app.PrepayRequest{
			Appid:         core.String(AppiD),
			Mchid:         core.String(Mchid),
			Description:   core.String(description),
			OutTradeNo:    core.String(outTradeNo),
			TimeExpire:    core.Time(endTime),
			Attach:        core.String(attach),
			NotifyUrl:     core.String(notifyUrl),
			GoodsTag:      core.String("WXG"),
			LimitPay:      []string{"no_credit"},
			SupportFapiao: core.Bool(false),
			Amount: &app.Amount{
				Currency: core.String("CNY"),
				Total:    core.Int64(amount),
			},
			SettleInfo: &app.SettleInfo{
				ProfitSharing: core.Bool(false),
			},
		},
	)

	if err != nil {
		// 处理错误
		return nil, err
	} else {
		// 处理返回结果
		//log.Printf("status=%d resp=%s", result.Response.StatusCode, resp)
	}
	result := make(map[string]interface{})
	//tmpJson := utils.GetJsonStr(resp)
	type PrepayWithRequestPaymentResponse1 struct {
		// 预支付交易会话标识
		PrepayId *string `json:"prepayid"` // revive:disable-line:var-naming
		// 商户号
		PartnerId *string `json:"partnerid"` // revive:disable-line:var-naming
		// 时间戳
		TimeStamp *string `json:"timestamp"`
		// 随机字符串
		NonceStr *string `json:"noncestr"`
		// 订单详情扩展字符串
		Package *string `json:"package"`
		// 签名
		Sign *string `json:"sign"`
	}
	resp1 := PrepayWithRequestPaymentResponse1{}
	resp1.PrepayId = resp.PrepayId
	resp1.PartnerId = resp.PartnerId
	resp1.TimeStamp = resp.TimeStamp
	resp1.NonceStr = resp.NonceStr
	resp1.Package = resp.Package
	resp1.Sign = resp.Sign
	tmpJson, _ := json.Marshal(resp1)
	json.Unmarshal([]byte(tmpJson), &result)

	return result, nil
}

type WxPayWechat struct {
	service.Service
}

func (e *WxPayWechat) AppPay(ctx context.Context, req *dto.WxPayReq) (appPayParams interface{}, err error) {
	//CreateWechatPrepayBill(req.OrderSn, req.Description, req.OrderType, req.TotalAmount)
	appPayParams, err = CreateWechatPrepayWithPayment(req.OrderSn, req.Description, req.OrderType, req.TotalAmount)
	return appPayParams, err
}

func (e *WxPayWechat) Notify(ctx *gin.Context, result *wechat.V3DecryptResult) error {
	notifyReq, err := wechat.V3ParseNotify(ctx.Request)
	if err != nil {
		return err
	}

	// wxPublicKey 通过 client.WxPublicKey() 获取
	client, err := wechat.NewClientV3(MchId, SerialNo, APIv3Key, PrivateKey)
	if err != nil {
		return err
	}
	wxPublicKey := client.WxPublicKey()
	err = notifyReq.VerifySignByPK(wxPublicKey)
	if err != nil {
		return err
	}

	// ========异步通知敏感信息解密========
	// 普通支付通知解密
	result, err = notifyReq.DecryptCipherText(APIv3Key)
	if err != nil {
		return err
	}
	return nil
}

func (e *WxPayWechat) Transfer(req *dto.TransferReq, student *models.TransferStudent) (resp *transferbatch.InitiateBatchTransferResponse, result *core.APIResult, err error) {
	// 使用 utils 提供的函数从本地文件中加载商户私钥，商户私钥会用来生成请求的签名
	var wxStudent api.SysWxStudent
	mchPrivateKey, err := payUtils.LoadPrivateKey(PrivateKey1)
	if err != nil {
		return nil, nil, err
	}

	ctx := context.Background()
	// 使用商户私钥等初始化 client，并使它具有自动定时获取微信支付平台证书的能力
	opts := []core.ClientOption{
		option.WithWechatPayAutoAuthCipher(Mchid, SerialNo, mchPrivateKey, APIv3Key),
	}
	client, err := core.NewClient(ctx, opts...)
	if err != nil {
		return nil, nil, err
	}
	err = e.Orm.Debug().Where("id = ?", req.StudentId).First(&student).Error
	if err != nil {
		return nil, nil, err
	}
	err = e.Orm.Debug().Where("student_id = ?",req.StudentId).First(&wxStudent).Error

	if err != nil {
		return nil, nil, err
	}

	if req.Amount > student.Balance {
		return nil, nil, errors.New("余额不足")
	}

	if student.Name == "" {
		return nil, nil, errors.New("请完善真实姓名")
	}

	if student.IdCard == "" {
		return nil, nil, errors.New("请完善身份证号码")
	}


	svc := transferbatch.TransferBatchApiService{Client: client}
	return svc.InitiateBatchTransfer(ctx,
		transferbatch.InitiateBatchTransferRequest{
			Appid:       core.String(APPID),
			BatchName:   core.String("商户转账"),
			BatchRemark: core.String("重庆拓维教育咨询有限公司-商户转账"),
			OutBatchNo:  core.String("TX" + adminDto.GenerateNum(time.Now())),
			TotalAmount: core.Int64(int64(req.Amount * 100)),
			TotalNum:    core.Int64(1),
			TransferDetailList: []transferbatch.TransferDetailInput{{
				TransferAmount: core.Int64(int64(req.Amount * 100)),
				UserName:       core.String(student.Name),
				OutDetailNo:    core.String("TX" + adminDto.GenerateNum(time.Now())),
				//UserIdCard:     core.String(student.IdCard),
				TransferRemark: core.String("余额提现"),
				Openid:         core.String(wxStudent.Openid),
			}},
		},
	)

}
